home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
Compilers⁄Interps
/
kevoSource
/
tasks.c
< prev
next >
Wrap
Text File
|
1993-05-10
|
11KB
|
464 lines
/* Kevo -- a prototype-based object-oriented language */
/* (c) Antero Taivalsaari 1991-1993 */
/* Some parts (c) Antero Taivalsaari 1986-1988 */
/* tasks.c: Task management internals */
#include "global.h"
/*--------------------------------------------------------------------------*/
/* Multitasking primitives */
/*
'yieldTo()' changes the desired task to be executed right now.
No checks are made whether the task is active, so you must be
very careful in using this operation.
*/
void yieldTo(thisTask)
TASK** thisTask;
{
/* Push earlier environment to the top of the current return stack */
storeExecEnv();
up = thisTask; /* Task switch occurs here!! */
/* Load new environment from the current return stack */
loadExecEnv();
}
/* Store the current execution environment frame to the return stack */
/*
Note that since this operation changes the contents of the return
stack, you cannot continue inner interpreter execution before
executing the corresponding loadExecEnv() operation.
*/
void storeExecEnv()
{
/* Depending on the machine architecture, select the faster implementation */
nPushReturn(3);
thirdReturn = (int*)contextSp;
secondReturn = (int*)dataSp;
topReturn = (int*)ip;
(*up)->rpStore = returnSp;
/*
pushReturn((int*)contextSp);
pushReturn((int*)dataSp);
pushReturn((int*)ip);
(*up)->rpStore = returnSp;
*/
}
/* Load the previous execution environment frame from the return stack */
void loadExecEnv()
{
/* Depending on the machine architecture, select the faster implementation */
returnSp = (*up)->rpStore;
ip = (int**)topReturn;
dataSp = secondReturn;
contextSp = (int**)thirdReturn;
nPopReturn(3);
/*
returnSp = (*up)->rpStore;
ip = (int**)popReturn();
dataSp = popReturn();
contextSp = (int**)popReturn();
*/
}
/* buildTask(): build a new background task */
/* The task shares the window with its creator */
TASK** buildTask()
{
/*
We copy the current task so the new task "inherits" all the
properties from the current task.
*/
TASK** newTask = (TASK**)copyObject(up);
TASK** tempUp;
/* New task needs its own execution stacks */
(*newTask)->returnStack = copyObject((*up)->returnStack);
(*newTask)->dataStack = copyObject((*up)->dataStack);
(*newTask)->contextStack = copyObject((*up)->contextStack);
/* New task has its own execution and textBuffer areas */
(*newTask)->trampoline = copyObject((*up)->trampoline);
(*newTask)->textBuffer = copyObject((*up)->textBuffer);
/* New task has also its own file stacks */
(*newTask)->infileStack = copyObject((*up)->infileStack);
(*newTask)->outfileStack = copyObject((*up)->outfileStack);
/* Initialize the text buffer */
eraseKeyBuffer(newTask);
/* Priority will be initialized to base priority */
(*newTask)->priority = basePriority;
/* Set the input and output files to 0 (terminal) */
tempUp = up;
up = newTask;
infile = 0;
outfile = 0;
errfile = 0;
infileSp = 0;
outfileSp = 0;
up = tempUp;
/* Set the initial behavior of the task to be 'boot' */
setTaskBehavior(newTask, oBoot);
/* Update the task link and number of tasks */
(*latestTask)->nextTask = newTask;
(*newTask)->nextTask = NIL;
latestTask = newTask;
taskCount++;
return(newTask);
}
/* previousRunningTask(): return the task that has its execution turn */
/* right before the given task (is located in front of it in the RR-chain) */
TASK** previousRunningTask(task)
TASK** task;
{
TASK** thisTask = (*up)->nextInRobin;
TASK** prevTask = up;
/*
Special case: If there is only one task in the round-robin chain,
and that is the requested task, return it.
*/
if (thisTask == prevTask) {
if (task == thisTask) return(up);
else return(FALSE);
}
while (thisTask != up) {
if (task == thisTask) return(prevTask);
prevTask = thisTask;
thisTask = (*thisTask)->nextInRobin;
}
if (task == thisTask) return(prevTask);
else return(FALSE);
}
/* isActivated(): check if a task is already in the round-robin chain */
int isActivated(task)
TASK** task;
{
TASK** thisTask = (*up)->nextInRobin;
/*
Special case: If there is only one task in the round-robin chain,
and that is the requested task.
*/
if (task == up) return(TRUE);
while (thisTask != up) {
if (task == thisTask) return(TRUE);
thisTask = (*thisTask)->nextInRobin;
}
return(FALSE);
}
/* Activate a task, allowing the task to continue its previous execution */
/* This operations operates only if the task is not already in the */
/* round-robin chain. */
void activateTask(thisTask)
TASK** thisTask;
{
if (!isActivated(thisTask)) {
TASK** temp = (*up)->nextInRobin;
(*up)->nextInRobin = thisTask;
(*thisTask)->nextInRobin = temp;
runningCount++;
}
}
/* Suspend a task (cancel its execution until it is reactivated) by */
/* removing it from the round-robin chain. This operation operates */
/* only if the task is in the round-robin chain, and the task is */
/* not the only running task in the system (because otherwise */
/* the system would die). */
int suspendTask(thisTask)
TASK** thisTask;
{
if (!isActivated(thisTask)) return(TRUE);
if ((runningCount == 1) || (!multitasking && thisTask == up)) {
/* Cannot suspend the only active task in the system */
return(FALSE);
}
else {
TASK** prevTask;
prevTask = previousRunningTask(thisTask);
(*prevTask)->nextInRobin = (*thisTask)->nextInRobin;
runningCount--;
return(TRUE);
}
}
/* Suspend a task and yield to the next task automatically */
int yieldingSuspend(thisTask)
TASK** thisTask;
{
int success;
if (runningCount == 1 && thisTask == up) return(FALSE);
/* If singletasking and there are other active tasks available */
if (!multitasking && thisTask == up && runningCount > 1) {
yieldTo((*up)->nextInRobin);
success = suspendTask(thisTask);
}
else {
success = suspendTask(thisTask);
yield();
}
return(success);
}
/* Reset the behavior of a task. The task must be in suspended state. */
/* The code to be executed is given as an object (handle). */
void setTaskBehavior(thisTask, behavior)
TASK** thisTask;
OBJECT* behavior;
{
TASK** tempUp = up;
int* currentContext = topContext;
if (isActivated(thisTask)) return;
/*
Change 'up' temporarily to 'thisTask' to allow easy initialization
of new task's execution environment.
*/
storeExecEnv();
up = thisTask;
/* Reset the stack pointers and set the instruction pointer (ip) */
initStacks();
ip = (int**)behavior->mfa;
/* Assignment count of the task must be zero initially */
(*thisTask)->assigning = 0;
/*
Context stack should normally never be empty.
Therefore, we push the current task's context to the
context stack of the new task.
*/
pushContext(currentContext);
/*
Initialize the execution environment of the new task.
'Yield' will then load the environment when it is the new task's turn.
*/
storeExecEnv();
/* Finally, return to the current 'up' and execution environment. */
up = tempUp;
loadExecEnv();
}
/* Delete a task provided that it is not running */
int deleteTask(thisTask)
TASK** thisTask;
{
if (!isActivated(thisTask)) {
/* Remove the task from the task list */
if (thisTask == firstTask) firstTask = (*firstTask)->nextTask;
else {
TASK** prevTask = firstTask;
while (prevTask) {
if (thisTask == (*prevTask)->nextTask) {
(*prevTask)->nextTask = (*thisTask)->nextTask;
break;
}
prevTask = (*prevTask)->nextTask;
}
if (thisTask == latestTask && prevTask) latestTask = prevTask;
}
/* Release memory and decrement the task counter */
deleteObject((OBJECT*)thisTask);
taskCount--;
return(TRUE); /* Task deleted successfully */
}
else return(FALSE); /* Task is currently running and cannot be deleted */
}
/*
This is a stronger version of 'deleteTask' which will
delete a task even if the task was currently running.
At least one task must however remain running, because otherwise
the system would crash.
*/
int killTask(thisTask)
TASK** thisTask;
{
if (yieldingSuspend(thisTask))
return(deleteTask(thisTask));
else return(FALSE); /* Cannot kill the only active task in the system */
}
/*
These special stack operations are needed to allow the
stacks of tasks to be initialized from other tasks.
*/
/* Push a value to the data stack of the given task */
void toTaskData(thisTask, data)
TASK** thisTask;
int data;
{
TASK** tempUp = up;
yieldTo(thisTask);
pushData(data);
yieldTo(tempUp);
}
/* Push a value to the return stack of the given task */
/* The task must not be active at the moment */
void toTaskReturn(thisTask, data)
TASK** thisTask;
int data;
{
if (!isActivated(thisTask)) {
TASK** tempUp = up;
yieldTo(thisTask);
pushReturn((int*)data);
yieldTo(tempUp);
}
}
/* Push a value to the context stack of the given task */
/* The task must not be active at the moment */
void toTaskCtxt(thisTask, data)
TASK** thisTask;
int data;
{
if (!isActivated(thisTask)) {
TASK** tempUp = up;
yieldTo(thisTask);
pushContext((int*)data);
yieldTo(tempUp);
}
}
/* resizeDataStack(): resize the data stack of the given task */
/* Since the location of stack's storage area may change, we must */
/* preserve the stack pointer using an offset */
/* The extra underflow area is added to the size */
void resizeDataStack(thisTask, newSize)
TASK** thisTask;
int newSize;
{
OBJECT* stack = (*thisTask)->dataStack;
TASK** tempUp = up;
int ptrOffset;
yieldTo(thisTask);
ptrOffset = (int*)dataSp - (int*)stack->mfa;
resizeClosure(stack, newSize + DATAOFFSET + UNDERFLOWRESERVE);
dataSp = (int*)stack->mfa + ptrOffset;
yieldTo(tempUp);
}
/* resizeReturnStack(): resize the return stack of the given task */
void resizeReturnStack(thisTask, newSize)
TASK** thisTask;
int newSize;
{
OBJECT* stack = (*thisTask)->returnStack;
TASK** tempUp = up;
int ptrOffset;
yieldTo(thisTask);
ptrOffset = (int*)returnSp - (int*)stack->mfa;
resizeClosure(stack, newSize + DATAOFFSET + UNDERFLOWRESERVE);
returnSp = (int**)((int*)stack->mfa + ptrOffset);
yieldTo(tempUp);
}
/* resizeContextStack(): resize the context stack of the given task */
void resizeContextStack(thisTask, newSize)
TASK** thisTask;
int newSize;
{
OBJECT* stack = (*thisTask)->contextStack;
TASK** tempUp = up;
int ptrOffset;
yieldTo(thisTask);
ptrOffset = (int*)contextSp - (int*)stack->mfa;
resizeClosure(stack, newSize + DATAOFFSET + UNDERFLOWRESERVE);
contextSp = (int**)((int*)stack->mfa + ptrOffset);
yieldTo(tempUp);
}
/* Get the "current working directory" (CWD) of the desired task */
/* CWD = the bottommost value in the context stack (see 'global.h') */
OBJECT* getTaskCWD(thisTask)
TASK** thisTask;
{
OBJECT* self;
TASK** tempUp = up;
up = thisTask;
self = (OBJECT*)CWD;
up = tempUp;
return(self);
}
/* Set the "current working directory" (CWD) of the desired task */
/* CWD = the bottommost value in the context stack (see in 'global.h') */
void setTaskCWD(thisTask, self)
TASK** thisTask;
OBJECT* self;
{
TASK** tempUp = up;
up = thisTask;
CWD = (int*)self;
up = tempUp;
}